<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <title>Hello World</title>
  </head>
  <body>
    
    <script>
      /*
        总结：
        1.类中的构造器不是必须写的，要对实例进行一些初始化的操作，如添加指定属性时才写。
        2.如果A类继承了B类，且A类中写了构造器，那么A类构造器中的super是必须要调用的。
        3.类中所定义的方法，都是放在了类的原型对象上，供实例去使用
      */


      class Person {
        // 构造器函数
        constructor(name, age) {
          // 构造器中的this是谁？--类的实例对象
          this.name = name;
          this.age = age;
        }
        //一般方法，除了构造器的方法
        speak() {
          // speak方法放在哪里？--类的原型对象上，供实例使用
          // 通过Person实例调用speak时，speak中的this就是Person实例对象
          console.log(`我叫${this.name},我年龄是${this.age}`);
        }
      }

      // 继承
      class Student extends Person {
        constructor(name, age, grade) {
          // 调用父类的构造器，super必须放在最前面
          super(name, age);
          this.grade = grade;
        }
        // 重写从父类继承来的方法
        speak() {
          console.log(`我叫${this.name},我年龄是${this.age},我在读${this.grade}年级`);
        }
        study() {
          console.log(`我正在读${this.grade}年级`);
        }
      }

      const p1 = new Person('tom', 18);
      const p2 = new Person('jery', 19);

      console.log(p1);//其中没有speak方法
      console.log(p2);

      console.log(p1.__proto__); //其中有speak方法

      p1.speak();
      p2.speak();


      const s1 = new Student('jack', 20, '1年级');
      console.log(s1);
      s1.speak();
      s1.study();

      class Car{
        constructor(brand, price){
          this.brand = brand;
          this.price = price;
        }
        // 类中可以直接写赋值语句,如下代码的含义是:给car的实例对象添加一个属性，名为a，值为1
        a = 1
      }
      const c1 = new Car('宝马', 100000);
      console.log(c1);
      

    </script>
  </body>
</html>